#include "common.h"


using namespace Scenic::Renderer;


ResourcePool imagePool;


Image::Image()
: Resource(&imagePool)
{
	width = 0;
	height = 0;
	blocks = 0;
}

Image::~Image()
{
	free();
}

Image *Scenic::Renderer::getImage(int id)
{
	return (Image*)imagePool.get(id);
}

ImageBlock *Image::getBlock(int row, int col)
{
	return &blocks[row * numCols + col];
}

void Image::free(bool isAsync)
{
	if(blocks)
	{
		for(int i = 0; i < numRows * numCols; i++)
			blocks[i].texture->release(isAsync);
		delete blocks;
		blocks = 0;
	}
}

void Image::updateJavaObject()
{
	jobject obj = getJavaObject();

	if(!obj)
		return;
	JNIEnvPtr env(getJavaVM());
	jclass clazz = env->GetObjectClass(obj);
	jfieldID widthField = env->GetFieldID(clazz, "width", "I");
	jfieldID heightField = env->GetFieldID(clazz, "height", "I");
	jfieldID formatField = env->GetFieldID(clazz, "format", "I");

	env->SetIntField(obj, widthField, width);
	env->SetIntField(obj, heightField, height);
	env->SetIntField(obj, formatField, format);
}

bool Image::create(int width, int height, Format format)
{
	int maxWidth = Device::getCaps().maxTextureWidth;
	int maxHeight = Device::getCaps().maxTextureHeight;

	if(width == 0 || height == 0)
		return true;
		
	this->format = format;
	this->width = width;
	this->height = height;
	numCols = 1 + (width - 1) / maxWidth;
	numRows = 1 + (height - 1) / maxHeight;

	blocks = new ImageBlock[numCols * numRows];

	for(int r = 0; r < numRows; r++)
	{
		int h = min(maxHeight, height - r * maxHeight);
		for(int c = 0; c < numCols; c++)
		{
			int w = min(maxWidth, width - c * maxWidth);
			ImageBlock *b = &blocks[r * numCols + c];

			b->texture = new Texture(w, h, format, 0);
			b->x = c * maxWidth;
			b->y = r * maxHeight;
			b->width = w;
			b->height = h;
		}
	}

	updateJavaObject();
	return true;
}

void Image::write(int x, int y, int width, int height, char *data, int pitch)
{
	int maxWidth = Device::getCaps().maxTextureWidth;
	int maxHeight = Device::getCaps().maxTextureHeight;

	if(pitch < 0)
	{
		data = data + (height - 1) * (-pitch) * Device::getFormatSize(format);
	}
	for(int r = 0; r < numRows; r++)
	{
		for(int c = 0; c < numCols; c++)
		{
			int left = c * maxWidth;
			int top = r * maxHeight;
			int right = min(left + maxWidth, this->width);
			int bottom = min(top + maxHeight, this->height);			
			int sLeft;
			int sRight;
			int sTop;
			int sBottom;
			int offset;
				
			sLeft = max(left, x);
			sTop = max(top, y);
			sRight = min(right, x + width);
			sBottom = min(bottom, y + height);
				
			offset = (sLeft - x + (sTop - y) * pitch) * Device::getFormatSize(format);
				
			blocks[r * numCols + c].texture->write(0, 
				sLeft - left, sTop - top, 
				sRight - sLeft, sBottom - sTop,
				data + offset, pitch);
		}
	}
}
